package com.eagle.support.helper;

import android.content.Intent;
import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
import android.text.TextUtils;
import android.util.Log;

import com.eagle.support.common.CallStatusManager;
import com.eagle.support.common.EventHandler;
import com.eagle.support.common.MessageHelper;
import com.eagle.support.utils.Utils;
import com.kinstalk.voip.sdk.EngineSdkAudioChannelState;
import com.kinstalk.voip.sdk.EngineSdkBiException;
import com.kinstalk.voip.sdk.EngineSdkCallInformation;
import com.kinstalk.voip.sdk.EngineSdkCallMode;
import com.kinstalk.voip.sdk.EngineSdkCallState;
import com.kinstalk.voip.sdk.EngineSdkDataChannelState;
import com.kinstalk.voip.sdk.EngineSdkInSessionNetworkQualityIndication;
import com.kinstalk.voip.sdk.EngineSdkUserRole;
import com.kinstalk.voip.sdk.EngineSdkVideoChannelState;
import com.kinstalk.voip.sdk.EngineSdkVideoPixelFormat;
import com.kinstalk.voip.sdk.api.WeaverService;
import com.kinstalk.voip.sdk.interfaces.WeaverRequestListener;
import com.kinstalk.voip.sdk.logic.sip.SipLogicApi;
import com.kinstalk.voip.sdk.logic.sip.aidl.model.CallInfo;
import com.kinstalk.voip.sdk.logic.sip.delegate.CallDataListener;
import com.kinstalk.voip.sdk.logic.sip.service.EngineLoader;
import com.kinstalk.voip.sdk.model.WeaverRequest;

import org.json.JSONException;
import org.json.JSONObject;
import org.json.JSONTokener;

import java.io.Serializable;
import java.util.HashMap;
import java.util.Map;
import java.util.Set;


/**
 * Created by gc on 2016/12/25.
 */

public class CallHelper implements Serializable, CallDataListener, EventHandler, WeaverRequestListener {

    private static final String TAG = "cim";

    protected String mRoomId = "00000000";

    protected String mChannelId = "0";

    private EngineSdkUserRole mUserRole;

    private EngineSdkCallMode mCallMode;

    protected String mCurLoginUser = "";

    protected IDataResultListener mDataListener;

    protected ICallStateListener mCallStateListener;

    protected IMeetingStateListener mMeetingStateListener;

    private EngineLoader mLoader;

    public HashMap<String, String> mJoinUserId = new HashMap<>();

    public String mRelayInfo;

    public String mRtmpUrl;

    //是否静音
    private boolean mSoundOff;

    //是否关闭涉嫌头
    private boolean mCameraOff;

    private static CallHelper sINSTANCE = null;

    private long mCallToken;

    private CallDataListener mGListener;

    private Handler mHandler = new Handler() {
        public void handleMessage(Message msg) {
            switch (msg.what) {
                case KEY_CALL_STATE:
                    callStateHandler((CallInfo) msg.obj, msg.arg1);
                    break;
                case KEY_CONFERENCE_CHANNELID_NOTIFY:
                    if (msg.arg1 == KEY_BYE_CID) {
                        onByeCid(String.valueOf(msg.obj));
                    } else {
                        Bundle bd = msg.getData();
                        onAddCid(bd.getString("channelid"), bd.getString("uid"));
                    }
                    break;
                case KEY_MESSAGE_RESULT:
                    int type = msg.arg1;
                    if (type == EventHandler.KEY_GOT_LIVE_ROOMID) {
                        mRoomId = (String) msg.obj;
                        mUserRole = EngineSdkUserRole.ES_UR_TYPE_MASTER;
                        if (mDataListener != null) mDataListener.onMessageSendResult(mRoomId);
                        MessageHelper.startLiveSecondStep(mRoomId, mCurLoginUser);
                    } else if (type == EventHandler.KEY_GOT_CONF_ROOMID) {
                        mRoomId = (String) msg.obj;
                        if (mMeetingStateListener != null)
                            mMeetingStateListener.onGotMeetingRoomResult(mRoomId);
                    }
                    break;
                case KEY_RING_MESSAGE:
                    onRingMessage((String) msg.obj);
                    break;
                case KEY_MESSAGE_NOTIFY:
                    Bundle bd = msg.getData();
                    if (mMeetingStateListener != null && bd != null)
                        mMeetingStateListener.onGotInviteResult(bd.getString("roomid"), bd.getString("sender"));
                    break;

            }
        }
    };

    private void onRingMessage(String msg) {
        if (null == msg)
            return;
        try {
            JSONTokener jsonParser = new JSONTokener(msg);
            JSONObject info = (JSONObject) jsonParser.nextValue();
            if (!info.isNull("live")) {
                JSONObject live = info.getJSONObject("live");
                mChannelId = live.getString("ChannelId");
                mRelayInfo = String.valueOf(live.getString("Relay"));
                if (!live.isNull("mRtmpUrl")) {
                    mRtmpUrl = String.valueOf(live.getString("RtmpUrl"));
                }
                Log.e(TAG, "onRingMessage: " + mChannelId);
            }
        } catch (JSONException e) {
            e.printStackTrace();
        }
    }

    private CallHelper() {
        this.mLoader = EngineLoader.getInstance();
        this.mLoader.getDataReceiver().setListener(this);
        this.mGListener = this.mLoader.getDataReceiver().getListener();

        WeaverService.getInstance().registerCallStateListener(CallStatusManager.getInstance());        // 注册通话事件监听
        WeaverService.getInstance().registerMessageStateListener(CallStatusManager.getInstance());     // 注册消息事件监听
        CallStatusManager.getInstance().setEventHandler(this);
    }

    public static CallHelper getInstance() {
        if (sINSTANCE == null) {
            sINSTANCE = new CallHelper();
        }
        return sINSTANCE;
    }

    public EngineLoader getLoader() {
        return this.mLoader;
    }


    public String getChannelId() {
        return mChannelId;
    }

    private void callStateHandler(CallInfo call, int state) {
        mCallToken = call.getCallConfiguration().getCallToken();
        switch (EngineSdkCallState.swigToEnum(state)) {
            case ES_STATE_ON_CALL_ANSWERING_CALL:
            case ES_STATE_ON_CALL_CALLING_OUT:
            case ES_STATE_ON_CALL_IN_ACTIVE_SESSION:
            case ES_STATE_ON_CALL_INCOMMING_CALL:
            case ES_STATE_ON_CALL_CALL_ENDED:
                if (mCallStateListener != null) mCallStateListener.onCallStateHandler(call, state);
                break;
            case ES_STATE_ON_CALL_RINGBACK_TONE:
                esStateOnCallRingbackTone(call);
                break;
        }
    }

    private void esStateOnCallRingbackTone(CallInfo call) {
        Log.e(TAG, "esStateOnCallRingbackTone: " + mCallMode);
        if (mCallMode == EngineSdkCallMode.ES_CM_TYPE_CONFERENCE_CLIENT) {
            String to = "mconf_";
            String message = "{\"conference\":{\"Cmd\":1," + "\"ShowMode\":1,\"RoomId\":" + mRoomId + ",\"Role\":" + String.valueOf(1 << mUserRole.ordinal()) + ",\"notify\": [{ \"channelid\":\"0000000000\", \"uid\":\"0000000000\" },{ \"channelid\":\"0000000000\", \"uid\":\"0000000000\" },{ \"channelid\":\"0000000000\", \"uid\":\"0000000000\" },{ \"channelid\":\"0000000000\", \"uid\":\"0000000000\" },{ \"channelid\":\"0000000000\", \"uid\":\"0000000000\" },{ \"channelid\":\"0000000000\", \"uid\":\"0000000000\" },{ \"channelid\":\"0000000000\", \"uid\":\"0000000000\" },{ \"channelid\":\"0000000000\", \"uid\":\"0000000000\" },{ \"channelid\":\"0000000000\", \"uid\":\"0000000000\" }]" + "}}";
            Log.e(TAG, "MESSAGE body: " + message);
            WeaverService.getInstance().dispatchRequest(SipLogicApi.sipSendMessage(to, message, null));
        }
    }

    public CallHelper roomId(String roomId) {
        this.mRoomId = roomId;
        return this;
    }

    public CallHelper userRole(int userRole) {
        this.mUserRole = EngineSdkUserRole.swigToEnum(userRole);
        return this;
    }

    public CallHelper callMode(int callMode) {
        this.mCallMode = EngineSdkCallMode.swigToEnum(callMode);
        return this;
    }

    public CallHelper uid(String uid) {
        this.mCurLoginUser = uid;
        return this;
    }

    public CallHelper registerDataResultListener(IDataResultListener listener) {
        this.mDataListener = listener;
        return this;
    }

    public CallHelper registerCallStateListener(ICallStateListener listener) {
        this.mCallStateListener = listener;
        return this;
    }

    public CallHelper registerMeetingStateListener(IMeetingStateListener listener) {
        this.mMeetingStateListener = listener;
        return this;
    }

    /**
     * 离开直播
     */
    public void quitLive() {
        if (mUserRole == EngineSdkUserRole.ES_UR_TYPE_MASTER && mCallMode == EngineSdkCallMode.ES_CM_TYPE_LIVE) {
            MessageHelper.sendLiveMsgBye(mRoomId, mChannelId, 4);
        }
        getLoader().endCall(getLoader().getCurrentCallInfo(), "");
    }

    //取消连麦
    public void leaveConnectBySlaver() {
        mUserRole = EngineSdkUserRole.ES_UR_TYPE_AUDIENCE;
        MessageHelper.sendLiveMsgBye(mRoomId, mChannelId, 2);
        WeaverService.getInstance().dispatchRequest(SipLogicApi.sipsetCallUserRole(mUserRole, null));
    }

    /**
     * 服务器异常, 停止直播请求
     */
    public void handlerServerError() {
        WeaverService.getInstance().dispatchRequest(SipLogicApi.stopPlaying(null));
        WeaverService.getInstance().dispatchRequest(SipLogicApi.sipEndCall(0, null));
    }


    public void onByeCid(String cid) {
        mJoinUserId.remove(cid);
        if (mDataListener != null) mDataListener.onPushByeCid(cid);
        WeaverService.getInstance().dispatchRequest(SipLogicApi.sipUpdateMediaChannel(String.valueOf(cid), false, null));
    }

    public void onAddCid(String cid, String uid) {
        Log.e(TAG, "onAddCid: " + cid + "-" + uid);
        if (!TextUtils.isEmpty(uid) && !TextUtils.isEmpty(mCurLoginUser) && Long.parseLong(cid) != 0) {
            if (uid.contains(mCurLoginUser)) {
                mChannelId = cid;
            } else {
                if (!mJoinUserId.containsKey(cid)) {
                    mJoinUserId.put(cid, uid);
                    if (mDataListener != null) mDataListener.onPushAddCid(cid);
                    WeaverService.getInstance().dispatchRequest(SipLogicApi.sipUpdateMediaChannel(cid, true, null));
                }
            }
        }
    }

    @Override
    public void onCallNetworkQualityChanged(EngineSdkInSessionNetworkQualityIndication engineSdkInSessionNetworkQualityIndication) {
        Log.e(TAG, "onCallNetworkQualityChanged: " + engineSdkInSessionNetworkQualityIndication.swigValue());
    }

    /**
     * 直播流回调
     */
    @Override
    public void onMainVideoData(long callToken, long pointer, int width, int height, char rotation, EngineSdkVideoPixelFormat format, long channelId) {
        if (mDataListener != null)
            mDataListener.onMainVideoDataInCall(callToken, pointer, width, height, rotation, format, channelId);
    }

    @Override
    public void onMainVideoReceiveStateChange(long l, EngineSdkVideoChannelState engineSdkVideoChannelState) {
        Log.e(TAG, "onMainVideoReceiveStateChange()");
    }

    @Override
    public void onMainVideoTransmitStateChange(long l, EngineSdkVideoChannelState engineSdkVideoChannelState) {
        Log.e(TAG, "onMainVideoTransmitStateChange()");
        // 从本地关闭视频接收到的通知，主要报告setTransmitingVideoPaused函数调用后的状态
        if (engineSdkVideoChannelState == EngineSdkVideoChannelState.ES_STATE_ON_VIDEO_CHANNEL_INACTIVE) {
            mCameraOff = true;
        } else {
            mCameraOff = false;
        }
    }

    public boolean isCameraOff() {
        return mCameraOff;
    }

    @Override
    public void on2ndVideoData(long l, long l1, int i, int i1, char c, EngineSdkVideoPixelFormat engineSdkVideoPixelFormat) {
        Log.e(TAG, "on2ndVideoData()");
    }

    @Override
    public void on2ndVideoStateChange(long l, EngineSdkVideoChannelState engineSdkVideoChannelState) {
        Log.e(TAG, "on2ndVideoStateChange()");
    }

    @Override
    public void onRequestPauseMainVideo(long l, boolean b, boolean b1) {
        Log.e(TAG, "onRequestPauseMainVideo()");
    }

    @Override
    public void onAudioReceiveStateChange(long l, EngineSdkAudioChannelState engineSdkAudioChannelState) {
        Log.e(TAG, "onAudioReceiveStateChange()" + engineSdkAudioChannelState.swigValue());
    }

    /**
     * 是否静音
     */
    public boolean isSoundOff() {
        return mSoundOff;
    }

    @Override
    public void onAudioTransmitStateChange(long l, EngineSdkAudioChannelState engineSdkAudioChannelState) {
        Log.e(TAG, "onAudioTransmitStateChange():" + l + "-" + engineSdkAudioChannelState.swigValue());
        if (engineSdkAudioChannelState == EngineSdkAudioChannelState.ES_STATE_ON_AUDIO_CHANNEL_MUTE) {
            mSoundOff = true;
        } else {
            mSoundOff = false;
        }
    }

    @Override
    public void onData(long l, byte[] bytes) {
        Log.e(TAG, "onData()");
    }

    @Override
    public void onDataStateChange(long l, EngineSdkDataChannelState engineSdkDataChannelState) {
        Log.e(TAG, "onDataStateChange()");
    }

    @Override
    public void onBiException(long l, EngineSdkBiException e, int i) {
        Log.e(TAG, "onBiException()");
    }

    @Override
    public void onMainVideoFilterSetResult(EngineSdkCallInformation engineSdkCallInformation, boolean b, long l) {
        Log.e(TAG, "onMainVideoFilterSetResult()");
    }

    @Override
    public void onMainVideoRecvVideoFilter(EngineSdkCallInformation engineSdkCallInformation, long l) {
        Log.e(TAG, "onMainVideoRecvVideoFilter()");
    }

    @Override
    public void onInfo(String s) {
        Log.e(TAG, "onInfo():" + s);
    }

    @Override
    public void onRecvRingingMsg(String s) {
        Log.e(TAG, "onRecvRingingMsg():" + s);
    }

    @Override
    public void onMainVideoChannelWonderfulSaved(EngineSdkCallInformation engineSdkCallInformation, String s) {
        Log.e(TAG, "onMainVideoChannelWonderfulSaved()");
    }

    @Override
    public Handler getHandler() {
        return mHandler;
    }

    @Override
    public void onRequestFinshed(WeaverRequest weaverRequest) {

    }

    public void handlerHeadsetPlug(Intent intent) {
        int state = intent.getIntExtra("state", -1);
        if (state == 1) {
            try {
                SipLogicApi.setEarphoneConnected(null, true);
            } catch (Exception e) {
                e.printStackTrace();
            }
        } else if (state == 0) {
            try {
                SipLogicApi.setEarphoneConnected(null, false);
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    }

    //连麦
    public void joinLiveBySlaver() {
        if (EngineSdkCallMode.ES_CM_TYPE_LIVE != mCallMode) {
            Log.e(TAG, "is not live mode, couldn`t join as slaver.");
            return;
        }

        if (EngineSdkUserRole.ES_UR_TYPE_AUDIENCE != mUserRole) {
            Log.e(TAG, "is not audience, couldn`t join as slaver.");
            return;
        }
        Log.e(TAG, "live mode, user role is " + mUserRole.toString() + " could join into live.");
        String to = "live_" + mRoomId;
        String message = "{\"live\":{\"Cmd\":1,\"ShowMode\":1,\"RoomId\":" + mRoomId +
                ",\"ChannelId\":" + mChannelId + ",\"Relay\":\"" + mRelayInfo + "\",\"Role\":2}}";

        Log.e(TAG, "MESSAGE body: " + message);
        WeaverService.getInstance().dispatchRequest(SipLogicApi.sipSendMessage(to, message, null));
        mUserRole = EngineSdkUserRole.ES_UR_TYPE_SLAVER;
        WeaverService.getInstance().dispatchRequest(SipLogicApi.sipsetCallUserRole(mUserRole, null));
    }

    /**
     * 开始呼叫
     */
    public void startCall(String to, String uid) {
        mCallMode = EngineSdkCallMode.ES_CM_TYPE_P2P;
        mUserRole = EngineSdkUserRole.ES_UR_TYPE_MASTER;
        WeaverService.getInstance().dispatchRequest(SipLogicApi.sipMakeCall(to, uid, false, null, mCallMode, mUserRole));
    }

    /**
     * 挂断
     */
    public void hangUpCall() {
        WeaverService.getInstance().dispatchRequest(SipLogicApi.sipEndCall((int) mCallToken, null));
    }

    /**
     * 接听来电
     */
    public void answeringCall() {
        WeaverService.getInstance().dispatchRequest(SipLogicApi.sipAnswerCall(false, null));
    }

    public void onDestory() {
        WeaverService.getInstance().unregisteCallStateListener(CallStatusManager.getInstance());
        WeaverService.getInstance().unregisteMessageStateListener(CallStatusManager.getInstance());
        CallStatusManager.getInstance().setEventHandler(null);
        if (this.mGListener.equals(this.mLoader.getDataReceiver().getListener())) {
            this.mLoader.getDataReceiver().setListener((CallDataListener) null);
            Log.e(TAG, "setListener set null");
        }
    }

    /**
     * 同意会议邀请
     */
    public void answerMeetingInvite(String roomId) {
        WeaverService.getInstance().dispatchRequest(
                SipLogicApi.sipMakeCall("mconf_" + roomId, mCurLoginUser, false, null,
                        EngineSdkCallMode.ES_CM_TYPE_CONFERENCE_CLIENT,
                        EngineSdkUserRole.ES_UR_TYPE_SLAVER));
    }

    /**
     * 开启会议
     */
    public void createMeeting(String info, boolean makeCall) {
        mCallMode = EngineSdkCallMode.ES_CM_TYPE_CONFERENCE_CLIENT;
        mUserRole = EngineSdkUserRole.ES_UR_TYPE_MASTER;
        Log.e(TAG, "createMeeting: " + mUserRole.toString() + "--mconf_" + info + "--" + mCurLoginUser + "--" + mRoomId);
        if (makeCall) {
            WeaverService.getInstance().dispatchRequest(SipLogicApi.sipMakeCall("mconf_" + info, mCurLoginUser, false, null, mCallMode, mUserRole));
        } else {
            MessageHelper.startConf(mUserRole, info);
        }
    }

    /**
     * 加入会议
     */
    public void joinMeeting(String roomId) {
        Log.e(TAG, "joinMeeting: " + "mconf_" + roomId + "--" + mCurLoginUser);
        WeaverService.getInstance().dispatchRequest(
                SipLogicApi.sipMakeCall("mconf_" + roomId, mCurLoginUser, false, null,
                        EngineSdkCallMode.ES_CM_TYPE_CONFERENCE_CLIENT,
                        EngineSdkUserRole.ES_UR_TYPE_SLAVER));
    }

    /**
     * 结束会议
     *
     * @param roomId
     */
    public void quitConference(String roomId) {
        String to = "mconf_";
        StringBuilder requestBody = new StringBuilder();
        StringBuilder participatorStr = new StringBuilder();
        if (mJoinUserId == null) {
            return;
        }
        if (!TextUtils.isEmpty(mChannelId) && !TextUtils.isEmpty(mRoomId)) {
            Set<Map.Entry<String, String>> sets = mJoinUserId.entrySet();
            for (Map.Entry<String, String> entry : sets) {
                String uid = entry.getValue();
                participatorStr.append(uid + " ");
            }

            requestBody.append("{\"conference\":{\"Cmd\":1,\"ShowMode\":1,");
            requestBody.append("\"Participator\":\"" + participatorStr.toString() + "\",");
            requestBody.append("\"ByeCid\":\"" + mChannelId + "\",\"Mode\":" + mCallMode.swigValue() + ",\"RoomId\":\"" + roomId + "\",");
            requestBody.append("\"Role\":" + (1 << mUserRole.swigValue()) + ",\"notify\": [");

            String flag = ",";
            for (int i = 1; i < 10; i++) {
                requestBody.append("{ \"channelid\":\"0000000000\", \"uid\":\"0000000000\" }");
                if (i < 9) {
                    requestBody.append(flag);
                }
            }
            requestBody.append("]}}\n");

            Log.e(TAG, "--- Master Quit Conference! msg=" + requestBody.toString());
            //发送退会请求
            WeaverService.getInstance().dispatchRequest(SipLogicApi.sipSendMessage(to, requestBody.toString(), null));
        }
        //发送退会请求
        WeaverService.getInstance().dispatchRequest(SipLogicApi.sipEndCall(0, null));
        requestBody.setLength(0);
        participatorStr.setLength(0);
        mJoinUserId.clear();
    }

    public CallHelper channelId(String channelId) {
        this.mChannelId = channelId;
        return this;
    }

    public CallHelper replayInfo(String relayInfo) {
        this.mRelayInfo = relayInfo;
        return this;
    }

    public void stopPlayIng() {
        SipLogicApi.stopPlaying(null);
    }

    public interface IDataResultListener {
        void onMessageSendResult(String roomId);

        void onPushAddCid(String cid);

        void onPushByeCid(String cid);

        void onMainVideoDataInCall(long callToken, long pointer, int width, int height, char rotation, EngineSdkVideoPixelFormat format, long channelId);
    }


    public interface ICallStateListener {
        void onCallStateHandler(CallInfo call, int state);
    }

    public interface IMeetingStateListener {
        /**
         * 获得邀请
         */
        void onGotInviteResult(String roomId, String sender);

        /**
         * 发起会议, 发送邀请
         */
        void onGotMeetingRoomResult(String roomId);
    }
}
